// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "StiffnessMatrixService.h"

#include <cstring>
#include <memory>

#include "DBManager/Common/ServiceMacro.h"
#include "DBManager/DBServiceFactory.h"

using namespace SG::DBManager;
using namespace SG::DataStructure::Common;

// 注册服务
SERVICE_REG_IMPL1 (StiffnessMatrixService, IStiffnessMatrixRepository)

StiffnessMatrixService::StiffnessMatrixService (IStiffnessMatrixRepository& repos) : m_repository (repos)
{}

StiffnessMatrixService::~StiffnessMatrixService () = default;

Status StiffnessMatrixService::Add (SG::DataStructure::FEM::ElementTypes etype, std::vector<SG::Algebra::Matrixd>& data)
{
    const size_t matrixSize = data.size ();
    if (matrixSize == 0)
    {
        return Status::STATUS_Success;
    }

    // 获取矩阵的行和列
    const size_t rows = data[0].GetRowSize ();
    const size_t cols = data[0].GetColSize ();

    // 矩阵大小
    const size_t matrixdSize = rows * cols;
    const size_t length      = matrixSize * matrixdSize + 2;

    // 构造写入数据
    std::vector<Real> writeData (length);

    Real* address = writeData.data ();  // 每次矩阵在writeData复制的首地址

    for (auto& curMatrix : data)
    {
        auto* MatrixDataBegin = curMatrix[0];
        std::memcpy (address, MatrixDataBegin, matrixdSize * sizeof (Real));
        address += matrixdSize;
    }

    // 最后面两个记录矩阵的行和列
    writeData[length - 2] = static_cast<Real> (rows);
    writeData[length - 1] = static_cast<Real> (cols);

    return m_repository.Add (etype, writeData);
}

Status StiffnessMatrixService::Get (SG::DataStructure::FEM::ElementTypes etype, std::vector<SG::Algebra::Matrixd>& _OUT data) const
{
    std::vector<Real> readData;

    if (m_repository.Get (etype, readData) == Status::STATUS_Success)
    {
        const auto rows        = static_cast<size_t> (readData[readData.size () - 2]);
        const auto cols        = static_cast<size_t> (readData[readData.size () - 1]);
        const auto matrixdSize = static_cast<int64_t> (rows * cols);

        auto iterBegin = readData.begin ();

        const std::size_t vecSize = readData.size () / matrixdSize;

        for (size_t i = 0; i < vecSize; i++)
        {
            data.emplace_back (rows, cols, std::vector<double> (iterBegin, iterBegin + matrixdSize));
            iterBegin += matrixdSize;
        }

        return Status::STATUS_Success;
    }

    return Status::STATUS_Failure;
}
